﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;

namespace Jenvin.Library.Helper
{
    public static class HtmlHelper
    {
        private static readonly Regex HtmlTagExpression = new Regex(@"(?'tag_start'</?)(?'tag'\w+)((\s+(?'attr'(?'attr_name'\w+)(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+)))?)+\s*|\s*)(?'tag_end'/?>)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static readonly Regex WhiteSpaceBetweenHtmlTagsExpression = new Regex(@">(/w+)<", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static readonly Regex HtmlLineBreakExpression = new Regex(@"<br(/s+)/>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        private static readonly Dictionary<string, List<string>> ValidHtmlTags = new Dictionary<string, List<string>> {
	{ "p", new List<string>() },
	{ "br", new List<string>() }, 
	{ "strong", new List<string>() }, 
	{ "b", new List<string>() }, 
	{ "em", new List<string>() }, 
	{ "i", new List<string>() }, 
	{ "u", new List<string>() }, 
	{ "strike", new List<string>() }, 
	{ "ol", new List<string>() }, 
	{ "ul", new List<string>() }, 
	{ "li", new List<string>() }, 
	{ "a", new List<string> { "href" } }, 
	{ "img", new List<string> { "src", "height", "width", "alt" } },
	{ "q", new List<string> { "cite" } }, 
	{ "cite", new List<string>() }, 
	{ "abbr", new List<string>() }, 
	{ "acronym", new List<string>() }, 
	{ "del", new List<string>() }, 
	{ "ins", new List<string>() }
};

        /// <summary>
        /// Toes the safe HTML.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <returns></returns>
        public static string ToSafeHtml(this string text)
        {
            return text
                .RemoveInvalidHtmlTags();
        }

        /// <summary>
        /// Removes the invalid HTML tags.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <returns></returns>
        public static string RemoveInvalidHtmlTags(this string text)
        {
            return HtmlTagExpression.Replace(text, new MatchEvaluator((Match m) =>
            {
                if (!ValidHtmlTags.ContainsKey(m.Groups["tag"].Value))
                    return String.Empty;

                string generatedTag = String.Empty;

                System.Text.RegularExpressions.Group tagStart = m.Groups["tag_start"];
                System.Text.RegularExpressions.Group tagEnd = m.Groups["tag_end"];
                System.Text.RegularExpressions.Group tag = m.Groups["tag"];
                System.Text.RegularExpressions.Group tagAttributes = m.Groups["attr"];

                generatedTag += (tagStart.Success ? tagStart.Value : "<");
                generatedTag += tag.Value;

                foreach (Capture attr in tagAttributes.Captures)
                {
                    int indexOfEquals = attr.Value.IndexOf('=');

                    // don't proceed any futurer if there is no equal sign or just an equal sign
                    if (indexOfEquals < 1)
                        continue;

                    string attrName = attr.Value.Substring(0, indexOfEquals);

                    // check to see if the attribute name is allowed and write attribute if it is
                    if (ValidHtmlTags[tag.Value].Contains(attrName))
                        generatedTag += " " + attr.Value;
                }

                // add nofollow to all hyperlinks
                if (tagStart.Success && tagStart.Value == "<" && tag.Value.Equals("a", StringComparison.OrdinalIgnoreCase))
                    generatedTag += " rel=\"nofollow\"";

                generatedTag += (tagEnd.Success ? tagEnd.Value : ">");

                return generatedTag;
            }));
        }

        private static Regex m_scriptTag = new Regex("<script[^>]*>[\\s\\S]*?</script>", RegexOptions.IgnoreCase);
        private static Regex m_spaceTag = new Regex("\\s+", RegexOptions.IgnoreCase);
        private static Regex m_htmlTag = new Regex("<[^>]*>", RegexOptions.IgnoreCase);
        public static string EscapeHTML(this string html)
        {
            html = m_scriptTag.Replace(html, "");
            html = m_htmlTag.Replace(html, "");
            html = m_spaceTag.Replace(html, " ");
            Hashtable hashReg = new Hashtable();
            //hashReg.Add("<!--.*?-->", "");

            /*
             * 使用正则委托，这样可以减少执行替换的次数，大大提高替换效率
             * 
             */
            hashReg.Add("&quot;", "\"");
            hashReg.Add("&#34;", "\"");
            hashReg.Add("&amp;", "&");
            hashReg.Add("&#38;", "&");
            hashReg.Add("&lt;", "<");
            hashReg.Add("&#60;", "<");
            hashReg.Add("&gt;", ">");
            hashReg.Add("&#62;", ">");
            hashReg.Add("&nbsp;", " ");
            hashReg.Add("&#160;", " ");
            hashReg.Add("&iexcl;", "\xa1");
            hashReg.Add("&#161;", "\xa1");
            hashReg.Add("&cent;", "\xa2");
            hashReg.Add("&#162;", "\xa2");
            hashReg.Add("&pound;", "\xa3");
            hashReg.Add("&#163;", "\xa3");
            hashReg.Add("&copy;", "\xa9");
            hashReg.Add("&#169;", "\xa9");
            hashReg.Add("&#\\d+;", " ");
            String[] arr = new String[hashReg.Count];
            hashReg.Keys.CopyTo(arr, 0);
            Regex reg = new Regex(String.Join("|", arr), RegexOptions.IgnoreCase | RegexOptions.Singleline);
            html = reg.Replace(html, delegate(Match m)
            {
                if (hashReg[m.Value] != null)
                    return hashReg[m.Value].ToString();
                return "";
            });
            return html.Trim();
            //return System.Web.HttpUtility.HtmlDecode(html);
        }
    }
}
